using IQIGame.Extension.Transfer;
using IQIGame.Onigao.Framework;
using IQIGame.Rendering;
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;

/// <summary>
/// 业务绑定Timeline
/// </summary>

[ExecuteAlways]
public class BehaviorFeatureComp : MonoBehaviour
{
    public TimelineAsset defaultTimelineAsset;
    [SerializeField]
    string toneShaderTitle = GameRender.ToneShaderTitle;

    PlayableDirector director;
    PlayableDirector Director
    {
        get
        {
            if (director == null)
                InitDirector();
            return director;
        }
    }

    TransferTimeline transfer;
    TransferTimeline Transfer
    {
        get
        {
            if (transfer == null)
                InitTransferTimeline();
            return transfer;
        }
    }
    Action defaultTimelineFinishedCall;

    void InitTransferTimeline()
    {
        transfer = new TransferTimeline(this.gameObject, toneShaderTitle);
        transfer.Prepare();
        if (defaultTimelineAsset != null)
            transfer.AddTimelineAsset(defaultTimelineAsset);
        if (FrameworkEntry.MonoDriver != null)
            FrameworkEntry.MonoDriver.updateEvent += transfer.OnUpdate;
    }

    void InitDirector()
    {
        director = gameObject.GetComponent<PlayableDirector>();
        if (director != null)
        {
            director.playOnAwake = false;
            if (director.playableAsset == null)
                director.playableAsset = defaultTimelineAsset;
        }
    }

    private void OnDestroy()
    {
        if (transfer != null)
        {
            transfer.Dispose();
            if (FrameworkEntry.MonoDriver != null)
                FrameworkEntry.MonoDriver.updateEvent -= transfer.OnUpdate;
        }

#if UNITY_EDITOR
        if (previewAsset != null)
            ExitPreviewAsset();
#endif
    }

    public void AddTimelineAsset(TimelineAsset track)
    {
        Transfer.AddTimelineAsset(track);
    }

    public void RemoveTimelineAsset(TimelineAsset track)
    {
        Transfer.RemoveTimelineAsset(track);
    }

    public void ClearTimelineAssets()
    {
        Transfer.ClearTimelineAssets();
    }

    /// <summary>
    /// 还原指定Timeline下所有Group
    /// </summary>
    public void ResotreTimeline(TimelineAsset asset)
    {
        Transfer.ResotreTimeline(asset);
    }

    /// <summary>
    /// 还原指定Timeline Group
    /// </summary>
    public void ResotreTimeline(TimelineAsset asset, string group)
    {
        Transfer.ResotreTimeline(asset, group);
    }

    /// <summary>
    /// 播放默认Timeline
    /// </summary>
    /// <param 播放完成后回调 = "onFinishedCall"></param>
    public void Play(Action onFinished = null)
    {
        if (defaultTimelineAsset != null)
            PlayTimelineAsset(defaultTimelineAsset, onFinished);
        else
            Debug.LogError("播放失败，未设置Timeline Asset");
    }

    /// <summary>
    /// 播放指定Timeline下所有Group
    /// </summary>
    public void PlayTimelineAsset(TimelineAsset asset, Action onFinished = null)
    {
        //存在Director时，回调由Director执行，否则由Transfer执行
        if (Director != null)
        {
            Director?.Play(asset);
            Director.stopped += OnDirectorFinished;
            Transfer.PlayTimeline(asset, onFinished);
        }
        else
        {
            Transfer.PlayTimeline(asset, onFinished);
        }
    }

    /// <summary>
    /// 播放默认Timeline的Group
    /// </summary>
    public void PlayGroup(string group, Action onFinishedCall = null)
    {
        if (defaultTimelineAsset != null)
            PlayTimelineAssetGroup(defaultTimelineAsset, group, onFinishedCall);
        else
            Debug.LogError("播放失败，未设置Timeline Asset");
    }

    /// <summary>
    /// 播放指定Timeline Group
    /// </summary>
    public void PlayTimelineAssetGroup(TimelineAsset asset, string group, Action onFinished = null)
    {
        Transfer.PlayTimeline(asset, group, onFinished);
    }

    void OnDirectorFinished(PlayableDirector director)
    {
        defaultTimelineFinishedCall?.Invoke();
        Director.stopped -= OnDirectorFinished;
    }

    public void StopAndRestore()
    {
        if (defaultTimelineAsset != null)
            ResotreTimeline(defaultTimelineAsset);
        Director?.Stop();
    }

    /// <summary>
    /// 暂停
    /// </summary>
    public void Pause()
    {
        Director?.Pause();
        Transfer.Pause = true;
    }

    /// <summary>
    /// 继续播放
    /// </summary>
    public void PlayContinue()
    {
        Director?.Play();
        Transfer.Pause = false;
    }

    public void SetTime(TimelineAsset asset, double time)
    {
        if (Director != null)
            Director.time = time;
        Transfer.SetTime(asset, (float)time);
    }
    public double DirectorDuration => Director?.duration ?? 0d;

    public void SetPlayableAsset(TimelineAsset asset)
    {
        defaultTimelineAsset = asset;
    }

    #region EditorMode
#if UNITY_EDITOR

    TimelineAsset previewAsset;
    List<DataTransferTrackBase> previewTracks = new List<DataTransferTrackBase>();

    public void EnterPreviewAsset(TimelineAsset asset)
    {
        //先还原一次，保证资源正确
        if (previewAsset != null)
            ExitPreviewAsset();

        previewAsset = asset;
        previewTracks.Clear();
        DataTransferUtility.GetTransferTracksList(previewAsset, ref previewTracks);

        for (int i = 0; i < previewTracks.Count; i++)
        {
            var clips = previewTracks[i].GetClips();
            Transfer.AddOrSetPreviewTrack(previewTracks[i], clips);
        }
    }

    public void ExitPreviewAsset()
    {
        for (int i = 0; i < previewTracks.Count; i++)
            Transfer.RestorePreview(previewTracks[i]);
        previewTracks.Clear();
        previewAsset = null;
    }

    public void Evalueate(TimelineAsset asset, double time)
    {
        SetTime(asset, time);
        Evalueate(asset);
    }

    public void Evalueate(TimelineAsset asset)
    {
        //保证数据正确，先进入一次预览模式
        if (previewAsset != asset)
            EnterPreviewAsset(asset);

        if (Director != null)
        {
            if (Director.playableAsset != asset)
                Director.playableAsset = asset;
            Director?.Evaluate();
        }

        float time = (float)Director.time;
        for (int i = 0; i < previewTracks.Count; i++)
            Transfer.EvaluatePreview(previewTracks[i], time);
    }
#endif
    #endregion
}
